package com.liz.lizrpccore.core.providers.redis;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.liz.lizrpccore.configs.RpcRedisConst;
import com.liz.lizrpccore.core.providers.AbstractLizRpc;
import com.liz.lizrpccore.core.providers.LizPrcProvider;
import com.liz.lizrpccore.entity.RemoteInvokeEntity;
import com.liz.lizrpccore.properties.LizRpcProperties;
import com.liz.lizrpccore.templates.excute.ExecutorServiceComponent;
import com.liz.lizrpccore.utils.SpringContextUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.List;

/**
 * @author liangGongWei
 * @description
 * @create 2021-08-25 18:15
 **/
@Slf4j
@Component
public class LizRpcRedisProvider extends AbstractLizRpc implements LizPrcProvider {

    @Override
    public void providerToRemote(List<String> classNameList,LizRpcProperties lizRpcProperties) {
        for (String className : classNameList) {
            try {
                Class<?> clazz = Class.forName(className);
                Class<?>[] interfaces = clazz.getInterfaces();
                assert interfaces.length >0;
                String interfaceName = interfaces[0].getName();
                String key = RpcRedisConst.getSaveRequestRedisKey(interfaceName);
                ExecutorServiceComponent.getDefaultExecutorService().execute(() -> {
                    while (true) {
                        boolean existsElement = this.getMyRedisTemplate().existsElement(key);
                        if (existsElement) {
                            // 取出并移出
                            String objectStr = this.getMyRedisTemplate().getAndRemoveFromList(key);
                            RemoteInvokeEntity entity = JSON.parseObject(objectStr, new TypeReference<RemoteInvokeEntity>() {
                            });
                            List<Object> args = this.getArgs(entity.getArgsList());
                            Object[] objects = args.toArray();
                            Object result = this.getResultFromContext(interfaceName, entity, objects);
                            // 将方法结果放到redis中
                            this.saveResultToRemote(result, interfaceName, entity);
                        }
                        try {
                            Thread.sleep(500L);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                });


            }catch (Exception e){
                log.info("获得class的接口名称异常，e：{}",e.getMessage());
            }

        }
    }

    private void saveResultToRemote(Object result, String className, RemoteInvokeEntity entity) {
        String key = RpcRedisConst.getSaveResultToRemoteRedisKey(className, entity.getClientId(), entity.getRequestId());
        String resStr = JSON.toJSONString(result);
        this.getMyRedisTemplate().setString(key, resStr);
    }


    private Object getResultFromContext(String className, RemoteInvokeEntity entity, Object[] params) {
        Object bean = SpringContextUtils.getApplicationContext().getBean(className);
        try {
            Class<? extends Object>[] paramClass = null;
            if (params != null) {
                int paramsLength = params.length;
                paramClass = new Class[paramsLength];
                for (int i = 0; i < paramsLength; i++) {
                    paramClass[i] = params[i].getClass();
                }
            }
            Method method = ReflectionUtils.findMethod(bean.getClass(), entity.getMethodName(), paramClass);
            if (method == null) {
                throw new RuntimeException("method: " + entity.getMethodName() + " not found-----");
            }
            return ReflectionUtils.invokeMethod(method, bean, params);
        } catch (Exception e) {
            throw new RuntimeException("bean: " + className + " not found-----");
        }
    }

}
